package cn.hmm;

import java.util.Collection;
import java.util.Map;
import java.util.Set;


public class HashMapMe<K,V> implements Map<K,V>{
     //inner helper class
	static class EntryMe<K,V>implements Map.Entry<K,V>{	 
		int hash;
		K key; V value;
		EntryMe<K,V> next;
		public EntryMe(int h,K key,V value,EntryMe<K,V> e){
			this.hash=h;this.key=key;this.value=value;this.next=e;}	 
		@Override
		public K getKey() {return key;}
		@Override
		public V getValue() {return value;}
		@Override
		public V setValue(V value) { V oldValue=this.value;this.value=value;return oldValue; }	
	}
	int fixedCapacity=1<<4;//16
	   //the essence of map	
	 private EntryMe<K,V>[] table;
	
	@SuppressWarnings("unchecked")
	public HashMapMe(){
    	table = new EntryMe[fixedCapacity];
    }	
/************************ put ************************************/
	@Override
	public V put(K key, V value) {
		//putForNullKey is not involve hash ,the hash is set into 0
		if (key == null){return putForNullKey(value);}	
		//now the key is not null,logic begin
		/********************************/
		int hash = hash(key);
		int index=this.indexFor(hash,fixedCapacity);
		EntryMe<K,V> e=table[index];
		while(e!=null){
			if((e.key==key)&&(e.hash==hash)){
				V oldValue=e.value;
				e.value=value;
				return oldValue;
			}
			e=e.next;
		}
		addEntryMe(hash,key,value,index);
		return null;
	}	 
	private V putForNullKey(V value) {
		//table[0]!=null
        for (EntryMe<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
            	V oldValue=e.value;e.value = value;
                return oldValue;
            }
        }
        //table[0]==null;
        addEntryMe(0,null,value,0);//hash,key,value,index
        return null;
    }
    void addEntryMe(int hash, K key, V value, int bucketIndex) {
        //ignore resize
        EntryMe<K,V> eBefor = table[bucketIndex];
        table[bucketIndex] = new EntryMe<>(hash,key,value,eBefor);
    }	
int hash(Object k) {
        int h=k.hashCode();
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
   }
int indexFor(int h, int length) {
        return h & (length-1); //hash%length
    }

/*********************  get **************************************/	
@Override
public V get(Object key) {
	if(key==null){
		return getForNullKey();
	}
	EntryMe<K,V> e = getEntryMe(key);
	return e==null?null:e.getValue();
}
public 	V getForNullKey(){
	Entry<K,V> e=table[0];
	return e.getValue();
}
public EntryMe<K,V> getEntryMe(Object key){
	int hash=hash(key);
	int index=this.indexFor(hash,fixedCapacity);
	EntryMe<K,V> e=table[index];
	while(e!=null){
	    if((e.hash==hash)&&(e.getKey()==key || key.equals(e.getKey()))){
	     return e;	
	    }
		e=e.next;
	}
	return null;
}	
	
//  not implement below methods	
	@Override
	public V remove(Object key) {
		return null;
	}
	@Override
	public void putAll(Map<? extends K, ? extends V> m) {		
	}
	@Override
	public void clear() {
	}
	@Override
	public Set<K> keySet() {
		return null;
	}
	@Override
	public Collection<V> values() {
		return null;
	}
	@Override
	public Set<java.util.Map.Entry<K, V>> entrySet() {
		return null;
	}
	@Override
	public int size() {
		return 0;
	}
	@Override
	public boolean isEmpty() {
		return false;
	}
	@Override
	public boolean containsKey(Object key) {
		return false;
	}
	@Override
	public boolean containsValue(Object value) {
		return false;
	}

}
